﻿using System;
using System.Security.Cryptography;
using System.Text;

namespace Mistral.Utils
{
	///<summary>
	/// Класс для генерации случайных чисел.
	/// В общем случае уникальность не гарантируется.
	///</summary>
	public class RandomGenerator
	{
		#region Fields

		private static readonly	RNGCryptoServiceProvider __rngCryptoServiceProvider = new RNGCryptoServiceProvider();
		private static readonly Random __random = new Random( Int32() );

		#endregion

		#region Guid

		/// <summary>
		/// Генерация случайного числа типа <see cref="Int32"/>
		/// с помощью <see cref="Guid"/>
		/// </summary>
		/// <returns>Int64</returns>
		public static Int32 Int32Guid()
		{
			return Guid.NewGuid().GetHashCode();
		}

		/// <summary>
		/// Генерация случайного числа типа <see cref="UInt32"/>
		/// с помощью <see cref="Guid"/>
		/// </summary>
		/// <returns>UInt32</returns>
		public static UInt32 UInt32Guid()
		{
			byte[] bytes = Guid.NewGuid().ToByteArray();
			return BitConverter.ToUInt32( bytes, 0 );
		}

		/// <summary>
		/// Генерация случайного числа типа <see cref="Int64"/>
		/// с помощью <see cref="Guid"/>
		/// </summary>
		/// <returns>Int64</returns>
		public static Int64 Int64Guid()
		{
			byte[] bytes = Guid.NewGuid().ToByteArray();
			return BitConverter.ToInt64( bytes, 0 );
		}

		/// <summary>
		/// Генерация случайного числа типа <see cref="UInt64"/>
		/// с помощью <see cref="Guid"/>
		/// </summary>
		/// <returns>UInt64</returns>
		public static UInt64 UInt64Guid()
		{
			byte[] bytes = Guid.NewGuid().ToByteArray();
			return BitConverter.ToUInt64( bytes, 0 );
		}

		#endregion

		#region RandomNumber

		/// <summary>
		/// Возвращает значение от 0 до 1
		/// </summary>
		public static double Random01()
		{
			uint i = UInt32();
			double d = ((double)i)/uint.MaxValue;
			return Math.Max( 0, Math.Min( 1, d ) );
		}

		/// <summary>
		/// Генерация случайного числа типа <see cref="Int32"/>
		/// </summary>
		/// <returns>Int32</returns>
		public static Int32 Int32()
		{
			byte[] bytes = new byte[4];
			__rngCryptoServiceProvider.GetBytes( bytes );
			return BitConverter.ToInt32( bytes, 0 );
		}

		/// <summary>
		/// Генерация случайного числа типа <see cref="UInt32"/>
		/// </summary>
		/// <returns>UInt32</returns>
		public static UInt32 UInt32()
		{
			byte[] bytes = new byte[4];
			__rngCryptoServiceProvider.GetBytes( bytes );
			return BitConverter.ToUInt32( bytes, 0 );
		}

		/// <summary>
		/// Генерация случайного числа типа <see cref="Int64"/>
		/// </summary>
		/// <returns>Int64</returns>
		public static Int64 Int64()
		{
			byte[] bytes = new byte[8];
			__rngCryptoServiceProvider.GetBytes( bytes );
			return BitConverter.ToInt64( bytes, 0 );
		}

		/// <summary>
		/// Генерация случайного числа типа <see cref="UInt64"/>
		/// </summary>
		/// <returns>UInt64</returns>
		public static UInt64 UInt64()
		{
			byte[] bytes = new byte[8];
			__rngCryptoServiceProvider.GetBytes( bytes );
			return BitConverter.ToUInt64( bytes, 0 );
		}

		#endregion

		#region RandomString

		/// <summary>
		/// Генерация случайной строки.
		/// В качестве символов строки используется набор "abcdefghijklmnopqrstuvwxyz1234567890"
		/// </summary>
		/// <param name="length">Длина строки</param>
		/// <returns>Сгенерированная строки</returns>
		public static string RandomString( int length )
		{
			const string charsToUse = "abcdefghijklmnopqrstuvwxyz1234567890";
			return RandomString( length, charsToUse );
		}

		/// <summary>
		/// Генерация случайной строки с заданными символами
		/// </summary>
		/// <param name="length">Длина строки</param>
		/// <param name="charsToUse">Символы для использования</param>
		/// <returns>Сгенерированная строки</returns>
		public static string RandomString( int length, string charsToUse )
		{
			// Массив символов
			char[] chars = charsToUse.ToCharArray();
		
			// Заполнение массива случайными числами
			byte[] data = new byte[length];
			__rngCryptoServiceProvider.GetNonZeroBytes( data );

			// Генерация строки
			StringBuilder result = new StringBuilder( length );
			foreach ( byte b in data )
			{
				result.Append( chars[b%( chars.Length - 1 )] );
			}
			return result.ToString();
		}

		#endregion

		/// <summary>
		/// Самая нечерьезная генерялка случайного числа.
		/// Используйте <see cref="Int32"/> или <see cref="Int32Guid"/>
		/// Оставлена для тестов.
		/// </summary>
		/// <returns>Int32</returns>
		public static Int32 Int32Random()
		{
			return __random.Next();
		}

	}
}
